package com.softer.wxzj.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.softer.wxzj.common.entity.CommonResult;
import com.softer.wxzj.common.entity.Page;
import com.softer.wxzj.common.enums.MessageEnum;
import com.softer.wxzj.common.enums.NumStrEnum;
import com.softer.wxzj.common.enums.NumberEnum;
import com.softer.wxzj.common.enums.ShiroResultEnum;
import com.softer.wxzj.common.error.CourseException;
import com.softer.wxzj.common.flow.enums.FlowStateEnum;
import com.softer.wxzj.common.flow.enums.FlowTypeEnum;
import com.softer.wxzj.common.flow.util.FlowAddAuditUtil;
import com.softer.wxzj.common.util.*;
import com.softer.wxzj.entity.*;
import com.softer.wxzj.mapper.*;
import com.softer.wxzj.service.ExpPayReqService;
import com.softer.wxzj.service.ExpPublicService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author Gong Zhiyang
 * @date 2019/7/17
 */
@Service
public class ExpPayReqServiceImpl implements ExpPayReqService {
    @Autowired
    private ExpPayReqMapper expPayReqMapper;
    @Autowired
    private ExpProjectReqMapper expProjectReqMapper;
    @Autowired
    private ExpProjectReqDetailMapper expProjectReqDetailMapper;
    @Autowired
    private ExpPayReqDetailMapper expPayReqDetailMapper;
    @Autowired
    private FlowAddAuditUtil flowAddAuditUtil;
    @Autowired
    private OperUtil zoneCodeUtil;
    @Autowired
    private SysCoreParamMapper syscoreparamMapper;
    @Autowired
    private ExpProjectReqServiceImpl expProjectReqService;
    @Autowired
    private FileServiceImpl fileService;
    @Autowired
    private BaseOwnerInfoMapper baseOwnerInfoMapper;
    @Autowired
    private ExpPublicService expPublicService;

    /**
     * 项目拨款管理列表
     *
     * @param page          分页实体
     * @param expProjectReq 查询实体
     * @return 列表
     */
    @Override
    public PageInfo<ExpProjectReq> getPayReqList(Page page, ExpProjectReq expProjectReq, String fuzzy) {
        String zoneCode = zoneCodeUtil.getZoneCode();
        expProjectReq.setZoneCode(zoneCode);
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<ExpProjectReq> list;
        //分为精确查询和模糊查询
        if (StringUtils.isBlank(fuzzy)) {
            list = expPayReqMapper.getPayReqList(expProjectReq);
        } else {
            list = expPayReqMapper.getPayReqListByFuzzy(fuzzy, zoneCode);
        }
        PageInfo<ExpProjectReq> info = new PageInfo<>(list);
        return info;
    }

    /**
     * 新增拨款管理
     *
     * @param expPayReqList list   拨款批次
     *                      isLast 是否存在质保金
     *                      num    拨款批次数
     *                      reqId  项目ID
     * @return 新增结果
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult add(ExpPayReqList expPayReqList) {
        return CommonResult.ResponseResult(insertExpPayReq(expPayReqList));
    }

    /**
     * 拨款管理拨款维护
     *
     * @param expPayReqList
     * @return
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult updateExpPayReqByList(ExpPayReqList expPayReqList) {
        expPayReqDetailMapper.deleteByReqId(expPayReqList.getReqId());
        int result = expPayReqMapper.deleteByReqId(expPayReqList.getReqId());

        if (result < 1) {
            throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
        }
        result = insertExpPayReq(expPayReqList);
        if (result < 1) {
            throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
        }
        return CommonResult.ResponseResult(result);
    }

    /**
     * 拨款管理的增加方法
     *
     * @param expPayReqList
     * @return
     */
    private int insertExpPayReq(ExpPayReqList expPayReqList) {
        int num = expPayReqMapper.countByReqId(expPayReqList.getReqId());
        ExpProjectReq expProjectReq = new ExpProjectReq();
        if (expPayReqList.getList().size() > 0) {
            expProjectReq = expProjectReqMapper.getInfoById(expPayReqList.getReqId());
        }
        //更新是否是质保金和付款次数
        expProjectReq.setIsLast(Integer.parseInt(expPayReqList.getIsLast()));
        //expProjectReq.setLastSum(lastSum);//待定 可能不存储
        expProjectReq.setPayCount(expPayReqList.getNum());

        BigDecimal payAmountSum = BigDecimal.ZERO;
        List<ExpPayReq> payReqList = new ArrayList<>();
        BigDecimal amount;
        if (expProjectReq.getFinish().equals(NumStrEnum.ONE.getNum())) {
            amount = expProjectReq.getFinalSum();
        } else {
            amount = expProjectReq.getCalculateBudgSum();
        }
        int payReqListSize = expPayReqList.getList().size();
        BigDecimal isLastSum = BigDecimal.ZERO;
        if (expProjectReq.getIsLast() == 1) {
            //是否质保金 0否 1 是
            isLastSum = amount.multiply(expPayReqList.getList().get(payReqListSize - 1).getPayRate()).multiply(new BigDecimal(0.01)).setScale(2, BigDecimal.ROUND_DOWN);
        }
        //拨款批次已经审核通过的金额总和
        BigDecimal payAmount_Sum = expPayReqMapper.payAmountSum(expPayReqList.getReqId());
        BigDecimal canUseFinalSum = amount.subtract(payAmount_Sum);
        //TODO 如果质保金金额>未拨款金额（canUseFinalSum），暂定质保金金额==未拨款金额（canUseFinalSum）
        if (isLastSum.compareTo(canUseFinalSum) > 0) {
            isLastSum = canUseFinalSum;
        }
        boolean flag = true;
        for (int i = 0; i < payReqListSize; i++) {
            ExpPayReq expPayReq = expPayReqList.getList().get(i);
            num++;
            if (expProjectReq.getIsLast() == 1 && num == expProjectReq.getPayCount()) {
                expPayReq.setIsFinalPay(NumStrEnum.ONE.getNum());
                expPayReq.setPayAmount(isLastSum);
                expProjectReq.setLastSum(isLastSum);
            } else {
                if (flag) {
                    if (expPayReq.getIsFinalPay() == "true") {
                        expPayReq.setIsFinalPay(NumStrEnum.ONE.getNum());
                        expPayReq.setPayAmount(amount.multiply(expPayReq.getPayRate()).multiply(new BigDecimal(0.01)).setScale(2, BigDecimal.ROUND_DOWN));
                    } else {
                        expPayReq.setIsFinalPay(NumStrEnum.ZERO.getNum());
                        expPayReq.setPayAmount(expProjectReq.getCalculateBudgSum().multiply(expPayReq.getPayRate()).multiply(new BigDecimal(0.01)).setScale(2, BigDecimal.ROUND_DOWN));
                    }
                    if ((payAmountSum.add(expPayReq.getPayAmount()).add(isLastSum)).compareTo(canUseFinalSum) >= 0) {
                        flag = false;
                        expPayReq.setPayAmount(canUseFinalSum.subtract(payAmountSum.add(isLastSum)));
                    }
                } else {
                    if (expPayReq.getIsFinalPay() == "true") {
                        expPayReq.setIsFinalPay(NumStrEnum.ONE.getNum());
                    } else {
                        expPayReq.setIsFinalPay(NumStrEnum.ZERO.getNum());
                    }
                    expPayReq.setPayAmount(BigDecimal.ZERO);
                }
            }
            payAmountSum = payAmountSum.add(expPayReq.getPayAmount());
            expPayReq.setReqId(expPayReqList.getReqId());
            expPayReq.setReqNum(num);
            expPayReq.setId(UUIDUtil.getUUID());
            String userName = ShiroUserUtil.getUserName();
            expPayReq.setCreater(userName);
            expPayReq.setCreateTime(DateUtils.getNow());
            expPayReq.setModifier(userName);
            expPayReq.setFlowState(NumStrEnum.ZERO.getNum());
            expPayReq.setStep(NumStrEnum.ZERO.getNum());
            expPayReq.setIsPrint(NumStrEnum.ZERO.getNum());
            expPayReq.setCurrentState(NumStrEnum.ONE.getNum());
            payReqList.add(expPayReq);
        }
        expProjectReqService.dealPay(payAmountSum, canUseFinalSum, payReqList, expProjectReq);
        for (ExpPayReq e : payReqList) {
            int count = expPayReqMapper.insert(e);
            if (count < 1) {
                return 0;
            }
        }
        if (expPayReqList.getIsLast().equals(NumStrEnum.ONE.getNum())) {
            //有质保金
            int size = expPayReqList.getList().size() - 1;
            ExpPayReq expPayReq = expPayReqList.getList().get(size);
            BigDecimal deptMoney = BigDecimal.ZERO;
            BigDecimal ableOrShare = BigDecimal.ZERO;
            List<ExpProjectReqDetail> expProjectReqDetailList = expProjectReqDetailMapper.GetInfoByReqId(expPayReq.getReqId());
            List<ExpPayReqDetail> list = new ArrayList<>();
            for (int i = 0; i < expProjectReqDetailList.size(); i++) {
                ExpPayReqDetail expPayReqDetail = new ExpPayReqDetail();
                expPayReqDetail.setId(UUIDUtil.getUUID());
                expPayReqDetail.setPayReqId(expPayReq.getId());
                expPayReqDetail.setReqId(expPayReq.getReqId());
                expPayReqDetail.setHouseId(expProjectReqDetailList.get(i).getRoomNo());
                expPayReqDetail.setCreateTime(DateUtils.getNow());
                expPayReqDetail.setCreater(ShiroUserUtil.getUserName());
                BaseOwnerInfo baseOwnerInfo = baseOwnerInfoMapper.selectOwner(expProjectReqDetailList.get(i).getRoomNo());
                if (null != baseOwnerInfo) {
                    expPayReqDetail.setOwnerId(baseOwnerInfo.getId());
                }

                this.grantApplySubElse(expProjectReq.getFinalSum() != null ? true : false, false, deptMoney, ableOrShare, expProjectReqDetailList.get(i), expPayReq, expPayReqDetail, null, expProjectReq);
                list.add(expPayReqDetail);
                deptMoney = expPayReqDetail.getDeptMoney();
                ableOrShare = expPayReqDetail.getAbleOrShare();
            }
            if ((ableOrShare.add(deptMoney)).compareTo(expPayReq.getPayAmount()) != 0) {
                BigDecimal[] bigDecimals = (expPayReq.getPayAmount().subtract(ableOrShare.add(deptMoney))).multiply(new BigDecimal(100)).divideAndRemainder(new BigDecimal(expProjectReqDetailList.size()));
                //整数部分
                if (bigDecimals[0].compareTo(BigDecimal.ZERO) > 0) {
                    for (ExpPayReqDetail expPayReqDetail : list) {
                        //数据库已拨付总金额
                        for (int i = 0; i < expProjectReqDetailList.size(); i++) {
                            if (expPayReqDetail.getHouseId() == expProjectReqDetailList.get(i).getRoomNo()) {
                                //可支配金额
                                BigDecimal governable;
                                if (expProjectReqDetailList.get(i).getActualGovernable() != null) {
                                    governable = expProjectReqDetailList.get(i).getActualGovernable();
                                } else {
                                    governable = expProjectReqDetailList.get(i).getGovernable();
                                }
                                //当拨付总金额=数据库已拨付总金额+此次拨款金额 < 可支配余额
                                if (expPayReqDetail.getMoney().compareTo(governable) < 0) {
                                    BigDecimal a = expPayReqDetail.getMoney().add(bigDecimals[0].divide(new BigDecimal(100)));
                                    expPayReqDetail.setMoney(a);
                                } else {
                                    BigDecimal a = expPayReqDetail.getSelfAmount().add(bigDecimals[0].divide(new BigDecimal(100)));
                                    expPayReqDetail.setSelfAmount(a);
                                }
                            }
                        }
                    }
                }
                //余数部分
                if (bigDecimals[1].compareTo(BigDecimal.ZERO) > 0) {
                    for (int i = 0; i < bigDecimals[1].intValue(); i++) {
                        ExpPayReqDetail expPayReqDetail1 = list.get(i);
                        //数据库已拨付总金额
                        for (int j = 0; j < expProjectReqDetailList.size(); j++) {
                            if (expPayReqDetail1.getHouseId() == expProjectReqDetailList.get(j).getRoomNo()) {
                                //可支配金额
                                BigDecimal governable;
                                if (expProjectReqDetailList.get(j).getActualGovernable() != null) {
                                    governable = expProjectReqDetailList.get(j).getActualGovernable();
                                } else {
                                    governable = expProjectReqDetailList.get(j).getGovernable();
                                }
                                //当拨付总金额=数据库已拨付总金额+此次拨款金额 < 可支配余额
                                if (expPayReqDetail1.getMoney().compareTo(governable) < 0) {
                                    BigDecimal a = expPayReqDetail1.getMoney().add(new BigDecimal(0.01));
                                    expPayReqDetail1.setMoney(a);
                                } else {
                                    BigDecimal a = expPayReqDetail1.getSelfAmount().add(new BigDecimal(0.01));
                                    expPayReqDetail1.setSelfAmount(a);
                                }

                            }
                        }
                    }
                }
            }
            //录入表pay_req_detail
            for (ExpPayReqDetail e : list) {
                expPayReqDetailMapper.insert(e);
            }
        }
        //质保金分摊
        return expProjectReqMapper.updateByPrimaryKeySelective(expProjectReq);
    }

    /**
     * 一般项目先公示，然后拨款申请，应急项目，只有决算拨款时，才需要过了公示期才能申请
     *
     * @param list          拨款集合
     * @param expProjectReq 项目信息
     * @param flag          公示标记
     * @return 公示标记
     */
    private boolean checkPublicDate(List<ExpPayReq> list, ExpProjectReq expProjectReq, boolean flag) {
        SysCoreParam sysParam = syscoreparamMapper.getInfo("31");
        //公示日期参数
        String param = sysParam.getParamCode() != null ? sysParam.getParamCode() : NumStrEnum.ZERO.getNum();
        //一般项目先公示，然后拨款申请，应急项目，只有决算拨款时，才需要过了公示期才能申请
        if (list != null && !list.isEmpty() && NumStrEnum.ONE.getNum().equals(expProjectReq.getProjectType())) {
            if (String.valueOf(NumberEnum.FOUR.getNum()).equals(expProjectReq.getStep()) && (Integer.parseInt(list.get(0).getFlowState()) == 0)) {
                LocalDateTime dateNow = LocalDateTime.now();
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime proReportDate = LocalDateTime.parse(expProjectReq.getProreportDate(), formatter);
                LocalDateTime publicDate = proReportDate.plusDays(Integer.parseInt(param));
                if (publicDate.isAfter(dateNow)) {
                    flag = false;
                }
            }
        }
        return flag;
    }

    /**
     * 设置按钮是否能使用
     *
     * @param expPayReq      拨款信息
     * @param isShowApplyBtn 是否显示拨款申请按钮
     * @param isShowOtherBtn 是否显示拨款申请按钮外其他按钮
     * @param msg            信息
     */
    private void setFlag(ExpPayReq expPayReq, String isShowApplyBtn, String isShowOtherBtn, String msg) {
        expPayReq.setIsShowApplyBtn(isShowApplyBtn);
        expPayReq.setIsShowOtherBtn(isShowOtherBtn);
        expPayReq.setMessage(msg);
    }

    /**
     * 查询紧急项目的决算拨款的先决条件
     *
     * @param expProjectReq 项目信息
     * @param expPayReq     拨款信息
     */
    public void checkPublic(ExpProjectReq expProjectReq, ExpPayReq expPayReq) {
        SysCoreParam sysParam = syscoreparamMapper.getInfo("64");
        //应急使用中，决算拨款的申请限制,如果不存在，默认公示后才能拨款申请(1公示后决算拨款，2决算拨款后公示)
        String param = sysParam.getParamCode() != null ? sysParam.getParamCode() : NumStrEnum.ONE.getNum();
        if (NumStrEnum.ONE.getNum().equals(param)) {
            ExpPublic info = expPublicService.getInfo(expProjectReq.getId(), null);
            if (info == null) {
                setFlag(expPayReq, NumStrEnum.ZERO.getNum(), NumStrEnum.ZERO.getNum(), "未维护公示期");
            } else {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime dateNow = LocalDateTime.now();
                LocalDateTime lastDate = LocalDateTime.parse(info.getEndTime(),df);
                if (dateNow.isAfter(lastDate)) {
                    setFlag(expPayReq, NumStrEnum.ONE.getNum(), NumStrEnum.ZERO.getNum(), "");
                } else {
                    setFlag(expPayReq, NumStrEnum.ZERO.getNum(), NumStrEnum.ZERO.getNum(), "公示期未结束，请等待。");
                }
            }
        }
    }

    /**
     * 检验质保金
     *
     * @param expProjectReq 项目信息
     * @param expPayReq     拨款信息
     */
    public void checkLast(ExpProjectReq expProjectReq, ExpPayReq expPayReq) {
        LocalDate dateNow = LocalDate.now();
        LocalDate lastDate = LocalDate.parse(expProjectReq.getWarrantyExpirationDate());
        if (dateNow.isAfter(lastDate)) {
            setFlag(expPayReq, NumStrEnum.ONE.getNum(), NumStrEnum.ZERO.getNum(), "");
        } else {
            setFlag(expPayReq, NumStrEnum.ZERO.getNum(), NumStrEnum.ZERO.getNum(), "当前日期是小于质保金返还日期，请等待。");
        }
    }

    /**
     * 如果第一次是决算后拨款
     *
     * @param result        是否已经竣工验收
     * @param expProjectReq 项目信息
     * @param list          拨款集合
     */
    private void checkFirstIsFinalPay(boolean result, ExpProjectReq expProjectReq, List<ExpPayReq> list) {
        if (result) {
            //而且是紧急项目，则必须过了公示期才能申请
            if (NumStrEnum.TWO.getNum().equals(expProjectReq.getProjectType())) {
                if (list.size() == NumberEnum.TWO.getNum() && expProjectReq.getIsLast() == 1) {
                    //如果只有两次拨款，而且最后一次是质保金拨款
                    checkPublic(expProjectReq, list.get(0));
                } else if (list.size() == 1) {
                    //如果只有一次拨款
                    checkPublic(expProjectReq, list.get(0));
                }
            } else {
                setFlag(list.get(0), NumStrEnum.ONE.getNum(), NumStrEnum.ZERO.getNum(), "");
            }
        } else {
            setFlag(list.get(0), NumStrEnum.ZERO.getNum(), NumStrEnum.ZERO.getNum(), "项目未竣工验收，请先完成项目验收。");
        }
    }

    /**
     * 最后一次拨款
     *
     * @param expProjectReq 项目信息
     * @param expPayReq     拨款信息
     */
    private void lastPay(ExpProjectReq expProjectReq, ExpPayReq expPayReq) {
        //最后一条如果是质保金，需要判断当前日期是否大于质保金日期
        if (expProjectReq.getIsLast() == 1) {
            checkLast(expProjectReq, expPayReq);
        } else {
            //最后一笔不是质保金，判断是否是应急使用，如果是应急使用，则必须在公示期结束后，才能拨款申请
            if (NumStrEnum.TWO.getNum().equals(expProjectReq.getProjectType())) {
                checkPublic(expProjectReq, expPayReq);
            } else {
                if (Integer.parseInt(expPayReq.getFlowState()) == 0) {
                    setFlag(expPayReq, NumStrEnum.ONE.getNum(), NumStrEnum.ZERO.getNum(), "");
                } else {
                    setFlag(expPayReq, NumStrEnum.ONE.getNum(), NumStrEnum.ONE.getNum(), "");
                }
            }
        }
    }

    /**
     * 最后一次拨款
     *
     * @param expProjectReq 项目信息
     * @param list          拨款集合
     * @param i             拨款批次
     */
    private void otherPay(ExpProjectReq expProjectReq, List<ExpPayReq> list, int i) {
        if (expProjectReq.getIsLast() == 1 && list.size() > 2 && NumStrEnum.TWO.getNum().equals(expProjectReq.getProjectType()) && i == list.size() - 2) {
            //如果最后一次是质保金拨款，而且拨款次数大于2次，则倒数第二次拨款为决算拨款，在紧急项目中，需要校验公示期
            checkPublic(expProjectReq, list.get(i));
        } else {
            if (Integer.parseInt(list.get(i).getFlowState()) == 0) {
                setFlag(list.get(i), NumStrEnum.ONE.getNum(), NumStrEnum.ZERO.getNum(), "");
            } else {
                setFlag(list.get(i), NumStrEnum.ONE.getNum(), NumStrEnum.ONE.getNum(), "");
            }
        }
    }

    /**
     * 项目审核通过
     *
     * @param list          拨款集合
     * @param expProjectReq 项目信息
     * @param num           拨款批次
     * @return 申请的批次
     */
    private int projectPassed(List<ExpPayReq> list, ExpProjectReq expProjectReq, int num) {
        //是否竣工标记
        boolean result = NumStrEnum.ONE.getNum().equals(expProjectReq.getFinish());
        //项目审核完成
        for (int i = 0; i < list.size(); i++) {
            num = i;
            //第一条
            if (i == 0) {
                list.get(i).setIsShowOtherBtn(NumStrEnum.ONE.getNum());
                if (Integer.parseInt(list.get(i).getFlowState()) == 1 || Integer.parseInt(list.get(i).getFlowState()) == 2) {
                    list.get(i).setIsShowApplyBtn(NumStrEnum.ZERO.getNum());
                    list.get(i).setMessage("此次拨款申请已提交");
                } else {
                    if (list.get(i).getIsFinalPay().equals(NumStrEnum.ONE.getNum())) {
                        //如果第一次是决算后拨款
                        checkFirstIsFinalPay(result, expProjectReq, list);
                    } else {
                        list.get(i).setIsShowApplyBtn(NumStrEnum.ONE.getNum());
                        if (Integer.parseInt(list.get(i).getFlowState()) == 0) {
                            list.get(i).setIsShowOtherBtn(NumStrEnum.ZERO.getNum());
                        }
                    }
                    //如果第一条还未申请，直接跳出，后面的不用循环了
                    break;
                }
            } else {
                if (list.get(i - 1).getStep().equals(NumStrEnum.FIVE.getNum())) {
                    if (Integer.parseInt(list.get(i).getFlowState()) == 1 || Integer.parseInt(list.get(i).getFlowState()) == 2) {
                        list.get(i).setIsShowApplyBtn(NumStrEnum.ZERO.getNum());
                        list.get(i).setMessage("此次拨款申请已提交");
                        continue;
                    }
                    if (list.get(i).getIsFinalPay().equals(NumStrEnum.ONE.getNum())) {
                        if (result) {
                            if (Integer.parseInt(list.get(i).getFlowState()) == 1 || Integer.parseInt(list.get(i).getFlowState()) == 2) {
                                list.get(i).setIsShowApplyBtn(NumStrEnum.ZERO.getNum());
                                list.get(i).setMessage("此次拨款申请已提交");
                            } else {
                                if (i == list.size() - 1) {
                                    lastPay(expProjectReq, list.get(i));
                                } else {
                                    otherPay(expProjectReq, list, i);
                                }
                                //如果当前条还未申请，直接跳出，后面的不用循环了
                                break;
                            }
                        } else {
                            setFlag(list.get(i), NumStrEnum.ZERO.getNum(), NumStrEnum.ZERO.getNum(), "项目未竣工验收，请先完成项目验收。");
                            break;
                        }
                    } else {
                        list.get(i).setIsShowApplyBtn(NumStrEnum.ONE.getNum());
                        if (Integer.parseInt(list.get(i).getFlowState()) == 0) {
                            list.get(i).setIsShowOtherBtn(NumStrEnum.ZERO.getNum());
                        } else {
                            //审核不通过
                            list.get(i).setIsShowOtherBtn(NumStrEnum.ONE.getNum());
                        }
                        //如果当前条还未申请，直接跳出，后面的不用循环了
                        break;
                    }
                } else {
                    setFlag(list.get(i), NumStrEnum.ZERO.getNum(), NumStrEnum.ZERO.getNum(), "前一批次拨款申请未完成，请等待。");
                    break;
                }
            }
        }
        return num;
    }

    /**
     * 获取拨款管理明细
     *
     * @param reqId   项目ID
     * @param arcType 图档类型
     * @return 拨款管理明
     * @auther cdg
     */
    @Override
    public List<ExpPayReq> getList(String reqId, String arcType) {
        List<ExpPayReq> list = expPayReqMapper.getList(reqId);
        //获取图档
        getFileTypeList(list, arcType);
        ExpProjectReq expProjectReq = expProjectReqMapper.getInfoById(reqId);
        boolean flag = true;
        //一般项目先公示，然后拨款申请，应急项目，只有决算拨款时，才需要过了公示期才能申请
        flag = checkPublicDate(list, expProjectReq, flag);
        int num = 0;
        boolean boo = (NumStrEnum.FOUR.getNum().equals(expProjectReq.getStep()) && flag) || NumStrEnum.SIX.getNum().equals(expProjectReq.getStep());
        int isLast = expProjectReq.getIsLast() != null ? expProjectReq.getIsLast() : 0;
        if (isLast == 1) {
            boo = (expProjectReq.getStep().equals(NumStrEnum.FOUR.getNum()) && flag) || expProjectReq.getStep().equals(NumStrEnum.SIX.getNum()) || expProjectReq.getStep().equals(NumStrEnum.SEVEN.getNum());
        }
        if (boo) {
            //项目审核完成
            num = projectPassed(list, expProjectReq, num);
            //跳出循环后，可用那一条后面的全部禁用，保证只有一条可用
            for (int i = num + 1; i < list.size(); i++) {
                setFlag(list.get(i), NumStrEnum.ZERO.getNum(), NumStrEnum.ZERO.getNum(), "前一批次拨款申请未完成，请等待。");
            }
        } else {
            for (int i = 0; i < list.size(); i++) {
                if (flag) {
                    setFlag(list.get(i), NumStrEnum.ZERO.getNum(), NumStrEnum.ZERO.getNum(), "项目未提交审核或处于审核中，请查看项目详情。");
                } else {
                    setFlag(list.get(i), NumStrEnum.ZERO.getNum(), NumStrEnum.ZERO.getNum(), "当前时间小于项目公示结束日期，请等待。");
                }
                if (NumStrEnum.EIGHT.getNum().equals(expProjectReq.getStep())) {
                    setFlag(list.get(i), NumStrEnum.ZERO.getNum(), NumStrEnum.ONE.getNum(), "已全部支付完成。");
                }
            }
        }
        return list;
    }

    /**
     * 获取图档
     *
     * @param list    拨款批次集合
     * @param arcType 图档类型
     */
    public void getFileTypeList(List<ExpPayReq> list, String arcType) {
        if (list != null && !list.isEmpty()) {
            for (ExpPayReq expPayReq : list) {
                // 查询图档信息
                List<FileVO> fileVOList = fileService.getFileVOList(expPayReq.getId(), arcType);
                expPayReq.setFileTypeList(fileVOList);
            }
        }
    }

    /**
     * 新增拨款管理
     *
     * @param expPayReqList list   拨款批次
     *                      isLast 是否存在质保金
     *                      num    拨款批次数
     *                      reqId  项目ID
     * @return 新增结果
     */
    @Override
    public CommonResult update(ExpPayReqList expPayReqList) {
        expPayReqMapper.delete(expPayReqList.getReqId());
        return add(expPayReqList);
    }

    /**
     * 拨款申请
     *
     * @param id 拨款ID
     * @return 申请状态
     */
    @Override
    public CommonResult updateState(String id, String operNo) {
        ExpPayReq expPayReq = new ExpPayReq();
        expPayReq.setId(id);
        expPayReq.setFlowState(String.valueOf(NumberEnum.ONE.getNum()));
        expPayReq.setModifier(StringUtils.isEmpty(operNo) ? ShiroUserUtil.getUserName() : operNo);
        return CommonResult.ResponseResult(expPayReqMapper.updateByPrimaryKeySelective(expPayReq));
    }

    /**
     * 查询是否进行过拨款申请
     *
     * @param reqId
     * @return
     */
    @Override
    public int getIsGrant(String reqId) {
        return expPayReqMapper.getIsGrant(reqId);
    }

    /**
     * 拨款申请
     *
     * @param expPayReq
     * @return
     * @auther cdg
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult grantApply(ExpPayReq expPayReq) {
        int num;
        ExpProjectReq expProjectReq = expProjectReqMapper.getInfoById(expPayReq.getReqId());
        List<ExpProjectReqDetail> expProjectReqDetailList = expProjectReqDetailMapper.GetInfoByReqId(expPayReq.getReqId());
        expPayReq = expPayReqMapper.getExpPayReqById(expPayReq.getId());
        if (!(expProjectReq.getIsLast() == 1 && expPayReq.getReqNum() == expProjectReq.getPayCount())) {
            //!(存在质保金，并且是最后一次拨款)
            expPayReqDetailMapper.deleteByPayReqId(expPayReq.getId());
        }
        //生成拨款申请编号
        expPayReq.setGrantreqNum(DepositUtil.getNo("9"));
        if (NumStrEnum.ONE.getNum().equals(expPayReq.getIsFinalPay())) {
            num = grantApplySub(expProjectReqDetailList, expPayReq, true, expProjectReq);
            if (num < 1) {
                throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
            }
        } else {
            num = grantApplySub(expProjectReqDetailList, expPayReq, false, expProjectReq);
            if (num < 1) {
                throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
            }
        }

        return CommonResult.ResponseResult(num);
    }

    /**
     * 拨款申请方法主体
     *
     * @param expProjectReqDetailList
     * @param expPayReq
     * @param isFinalPay
     * @return
     */

    private int grantApplySub(List<ExpProjectReqDetail> expProjectReqDetailList, ExpPayReq expPayReq, boolean isFinalPay, ExpProjectReq expProjectReq) {
        int num;
        //用户自交总计
        BigDecimal deptMoney = BigDecimal.ZERO;
        //系统支付总计
        BigDecimal ableOrShare = BigDecimal.ZERO;

        List<ExpPayReqDetail> list = new ArrayList();
        //查询当前批次的下一次拨付金额是否为0
        int reqNum = expPayReq.getReqNum() + 1;
        int payCount = expProjectReq.getPayCount();
        if (expProjectReq.getIsLast() == 1) {
            payCount = payCount - 1;
        }
        //若当前批次下一次拨付金额为0，则此次的每一业主的分摊金额不根据比例计算
        boolean flag = false;
        if (reqNum <= payCount) {
            ExpPayReq nextPayInfo = expPayReqMapper.getLastSumById(expPayReq.getReqId(), reqNum);
            if (nextPayInfo.getPayAmount().compareTo(BigDecimal.ZERO) == 0) {
                flag = true;
                isFinalPay = true;
            }
        }

        if (expPayReq.getPayAmount().compareTo(BigDecimal.ZERO) > 0) {
            for (int i = 0; i < expProjectReqDetailList.size(); i++) {
                //录入pay_req_detail表的公共部分
                ExpPayReqDetail expPayReqDetail = new ExpPayReqDetail();
                expPayReqDetail.setId(UUIDUtil.getUUID());
                expPayReqDetail.setPayReqId(expPayReq.getId());
                expPayReqDetail.setReqId(expPayReq.getReqId());
                expPayReqDetail.setHouseId(expProjectReqDetailList.get(i).getRoomNo());
                expPayReqDetail.setCreateTime(DateUtils.getNow());
                expPayReqDetail.setCreater(ShiroUserUtil.getUserName());
                //业主已拨付总金额
                ExpPayReqDetail expPayReqDetailSum = expPayReqDetailMapper.getSumByReqId(expProjectReqDetailList.get(i).getReqId(), expProjectReqDetailList.get(i).getRoomNo());
                if (expProjectReq.getIsLast() == 1) {

                    //是否质保金 0否 1 是
                    if (expPayReq.getReqNum() != expProjectReq.getPayCount()) {
                        this.grantApplySubElse(isFinalPay, flag, deptMoney, ableOrShare, expProjectReqDetailList.get(i), expPayReq, expPayReqDetail, expPayReqDetailSum, expProjectReq);
                    } else {
                        //质保金拨款
                        expPayReqDetail = expPayReqDetailMapper.getInfoByPayReqIdAndHouseId(expPayReq.getId(), expProjectReqDetailList.get(i).getRoomNo());
                        ableOrShare = ableOrShare.add(expPayReqDetail.getMoney());
                        deptMoney = deptMoney.add(expPayReqDetail.getSelfAmount());
                        expPayReqDetail.setDeptMoney(deptMoney);
                        expPayReqDetail.setAbleOrShare(ableOrShare);
                    }
                } else {
                    this.grantApplySubElse(isFinalPay, flag, deptMoney, ableOrShare, expProjectReqDetailList.get(i), expPayReq, expPayReqDetail, expPayReqDetailSum, expProjectReq);
                }

                deptMoney = expPayReqDetail.getDeptMoney();
                ableOrShare = expPayReqDetail.getAbleOrShare();
                list.add(expPayReqDetail);
            }
        } else {
            for (int i = 0; i < expProjectReqDetailList.size(); i++) {
                //录入pay_req_detail表的公共部分
                ExpPayReqDetail expPayReqDetail = new ExpPayReqDetail();
                expPayReqDetail.setId(UUIDUtil.getUUID());
                expPayReqDetail.setPayReqId(expPayReq.getId());
                expPayReqDetail.setReqId(expPayReq.getReqId());
                expPayReqDetail.setHouseId(expProjectReqDetailList.get(i).getRoomNo());
                expPayReqDetail.setCreateTime(DateUtils.getNow());
                expPayReqDetail.setCreater(ShiroUserUtil.getUserName());
                expPayReqDetail.setMoney(BigDecimal.ZERO);
                expPayReqDetail.setSelfAmount(BigDecimal.ZERO);
                BaseOwnerInfo baseOwnerInfo = baseOwnerInfoMapper.selectOwner(expProjectReqDetailList.get(i).getRoomNo());
                if (null != baseOwnerInfo) {
                    expPayReqDetail.setOwnerId(baseOwnerInfo.getId());
                }
                list.add(expPayReqDetail);
            }
        }
        if ((ableOrShare.add(deptMoney)).compareTo(expPayReq.getPayAmount()) != 0) {
            BigDecimal[] bigDecimals = (expPayReq.getPayAmount().subtract(ableOrShare.add(deptMoney))).multiply(new BigDecimal(100)).divideAndRemainder(new BigDecimal(expProjectReqDetailList.size()));
            //整数部分
            if (bigDecimals[0].compareTo(BigDecimal.ZERO) > 0) {
                for (ExpPayReqDetail e : list) {
                    //数据库已拨付总金额
                    BigDecimal money = expProjectReqMapper.getSumByReqId(e) != null ? expProjectReqMapper.getSumByReqId(e) : BigDecimal.ZERO;
                    for (int i = 0; i < expProjectReqDetailList.size(); i++) {
                        if (e.getHouseId().equals(expProjectReqDetailList.get(i).getRoomNo())) {
                            //可支配金额
                            BigDecimal governable;
                            if (isFinalPay) {
                                governable = expProjectReqDetailList.get(i).getActualGovernable();
                            } else {
                                governable = expProjectReqDetailList.get(i).getGovernable();
                            }
                            //当拨付总金额=数据库已拨付总金额+此次拨款金额 < 可支配余额
                            if ((money.add(e.getMoney())).compareTo(governable) < 0) {
                                BigDecimal a = e.getMoney().add(bigDecimals[0].divide(new BigDecimal(100)));
                                e.setMoney(a);
                                ableOrShare = ableOrShare.add(bigDecimals[0].divide(new BigDecimal(100)));

                            } else {
                                BigDecimal a = e.getSelfAmount().add(bigDecimals[0].divide(new BigDecimal(100)));
                                e.setSelfAmount(a);
                                deptMoney = deptMoney.add(bigDecimals[0].divide(new BigDecimal(100)));
                            }
                        }
                    }
                }
            }
            //余数部分
            if (bigDecimals[1].compareTo(BigDecimal.ZERO) > 0) {
                for (int i = 0; i < bigDecimals[1].intValue(); i++) {
                    ExpPayReqDetail e1 = list.get(i);
                    //数据库已拨付总金额
                    BigDecimal money = expProjectReqMapper.getSumByReqId(e1) != null ? expProjectReqMapper.getSumByReqId(e1) : BigDecimal.ZERO;
                    for (int j = 0; j < expProjectReqDetailList.size(); j++) {
                        if (e1.getHouseId().equals(expProjectReqDetailList.get(j).getRoomNo())) {
                            //可支配金额
                            BigDecimal governable;
                            if (isFinalPay) {
                                governable = expProjectReqDetailList.get(j).getActualGovernable();
                            } else {
                                governable = expProjectReqDetailList.get(j).getGovernable();
                            }
                            //当拨付总金额=数据库已拨付总金额+此次拨款金额 < 可支配余额
                            if ((money.add(e1.getMoney())).compareTo(governable) < 0) {
                                BigDecimal a = e1.getMoney().add(new BigDecimal(0.01));
                                e1.setMoney(a);
                                ableOrShare = ableOrShare.add(new BigDecimal(0.01));

                            } else {
                                BigDecimal a = e1.getSelfAmount().add(new BigDecimal(0.01));
                                e1.setSelfAmount(a);
                                deptMoney = deptMoney.add(new BigDecimal(0.01));
                            }

                        }
                    }
                }
            }
        }
        //录入表pay_req_detail
        for (ExpPayReqDetail expPayReqDetail1 : list) {
            if (expProjectReq.getIsLast() == 1 && expPayReq.getReqNum() == expProjectReq.getPayCount()) {
                //num = 0;
            } else {
                num = expPayReqDetailMapper.insert(expPayReqDetail1);
            }
        }
        expPayReq.setPayAmount(ableOrShare.add(deptMoney));
        expPayReq.setSystemPayment(ableOrShare);
        expPayReq.setSelfAmount(deptMoney);
        expPayReq.setFlowState(String.valueOf(NumberEnum.ONE.getNum()));
        expPayReq.setStep(String.valueOf(NumberEnum.ONE.getNum()));
        //绑定审批流 并更新拨款申请人和申请时间
        String initState = flowAddAuditUtil.initFlow(expPayReq.getId(), FlowTypeEnum.PAY_REQ.getType(), null);
        expPayReq.setGrantreqUser(ShiroUserUtil.getUser().getOperName());
        expPayReq.setGrantreqDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        //当返回通过NumStrEnum.TWO.getNum()时 表明该记录不需要审核，直接更新到业务表
        if (FlowStateEnum.PASS.getState().equals(initState)) {
            //审核通过
            expPayReq.setFlowState(String.valueOf(NumberEnum.TWO.getNum()));
            expPayReq.setStep(String.valueOf(NumberEnum.SIX.getNum()));
            expPayReq.setGrantcompletionDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        }
        num = expPayReqMapper.updateByPrimaryKey(expPayReq);
        return num;
    }

    /**
     * rantApplySub的else封装
     *
     * @param isFinalPay          是否决算后付款
     * @param deptMoney
     * @param ableOrShare
     * @param expProjectReqDetail
     * @param expPayReq
     * @return
     */
    private void grantApplySubElse(boolean isFinalPay, boolean flag, BigDecimal deptMoney, BigDecimal ableOrShare, ExpProjectReqDetail expProjectReqDetail, ExpPayReq expPayReq, ExpPayReqDetail expPayReqDetail, ExpPayReqDetail expPayReqDetailSum, ExpProjectReq expProjectReq) {
        int deptMoneyCont;//欠款金额对比用
        int ableOrShareCont;//可用金额或决算分摊金额对比用
        BigDecimal amount;//应交总金额
        BigDecimal governable;//可用总金额
        BigDecimal moneySum = expPayReqDetailSum != null ? expPayReqDetailSum.getMoney() : BigDecimal.ZERO;
        BigDecimal selfMoneySum = expPayReqDetailSum != null ? expPayReqDetailSum.getSelfAmount() : BigDecimal.ZERO;
        if (isFinalPay) {
            amount = expProjectReqDetail.getActualAmount();
            governable = expProjectReqDetail.getActualGovernable();
            deptMoneyCont = expProjectReqDetail.getActualDept().compareTo(BigDecimal.ZERO);
            ableOrShareCont = expProjectReqDetail.getActualGovernable().compareTo(BigDecimal.ZERO);
        } else {
            amount = expProjectReqDetail.getAssiAmount();
            governable = expProjectReqDetail.getGovernable();
            deptMoneyCont = expProjectReqDetail.getAssiDept().compareTo(BigDecimal.ZERO);
            ableOrShareCont = expProjectReqDetail.getGovernable().compareTo(BigDecimal.ZERO);
        }
        if (deptMoneyCont > 0 && ableOrShareCont == 0) {
            //全部用户自缴
            expPayReqDetail.setMoney(BigDecimal.ZERO);
            expPayReqDetail.setSelfAmount(amount.multiply(expPayReq.getPayRate()).multiply(new BigDecimal(0.01)).setScale(2, BigDecimal.ROUND_DOWN));
            if (expProjectReq.getIsLast() == 1) {
                //是否质保金 0否 1 是
                if (expPayReq.getReqNum() == (expProjectReq.getPayCount() - 1) || flag) {
                    //倒数第二次的计算 不按比例计算
                    //倒数第二次拨款金额 = 应付总金额 - 已拨付金额(已经包含质保金 在竣工验收时以如表pay_req_detail)
                    expPayReqDetail.setSelfAmount(amount.subtract(selfMoneySum).subtract(moneySum));
                }
            } else {
                //非质保金
                if (expPayReq.getReqNum() == expProjectReq.getPayCount() || flag) {
                    //最后一次拨款
                    expPayReqDetail.setSelfAmount(amount.subtract(selfMoneySum).subtract(moneySum));
                }
            }
            deptMoney = deptMoney.add(expPayReqDetail.getSelfAmount());

        } else if (deptMoneyCont == 0 && ableOrShareCont > 0) {
            //全部系统支付
            expPayReqDetail.setSelfAmount(BigDecimal.ZERO);
            expPayReqDetail.setMoney(amount.multiply(expPayReq.getPayRate()).multiply(new BigDecimal(0.01)).setScale(2, BigDecimal.ROUND_DOWN));
            if (expProjectReq.getIsLast() == 1) {
                //是否质保金 0否 1 是
                if (expPayReq.getReqNum() == (expProjectReq.getPayCount() - 1) || flag) {
                    //倒数第二次的计算 不按比例计算
                    //倒数第二次拨款金额 = 应付总金额 - 已拨付金额(已经包含质保金 在竣工验收时以如表pay_req_detail)
                    expPayReqDetail.setMoney(amount.subtract(moneySum).subtract(selfMoneySum));
                }
            } else {
                //非质保金
                if (expPayReq.getReqNum() == expProjectReq.getPayCount() || flag) {
                    //最后一次拨款
                    expPayReqDetail.setMoney(amount.subtract(moneySum).subtract(selfMoneySum));
                }
            }
            ableOrShare = ableOrShare.add(expPayReqDetail.getMoney());

        } else if (deptMoneyCont > 0 && ableOrShareCont > 0) {
            //本次拨款业主应交金额
            BigDecimal money = (amount.multiply(expPayReq.getPayRate()).multiply(new BigDecimal(0.01)).setScale(2, BigDecimal.ROUND_DOWN));
            // 预留质保金
            //还有剩余可支配余额 = 系统应交 - 已拨付金额(包含质保金)
            BigDecimal ky = governable.subtract(moneySum);
            if (expProjectReq.getIsLast() == 1) {
                if (expPayReq.getReqNum() == (expProjectReq.getPayCount() - 1) || flag) {
                    //倒数第二次
                    money = amount.subtract(moneySum).subtract(selfMoneySum);
                }
            } else {
                //非质保金
                if (expPayReq.getReqNum() == expProjectReq.getPayCount() || flag) {
                    //最后一次拨款
                    money = amount.subtract(moneySum).subtract(selfMoneySum);
                }
            }
            if (ky.compareTo(BigDecimal.ZERO) > 0) {
                int moneyNum = money.compareTo(ky);
                if (moneyNum <= 0) {
                    //剩余可支配余额比此次拨款金额大
                    expPayReqDetail.setSelfAmount(BigDecimal.ZERO);
                    expPayReqDetail.setMoney(money);
                    ableOrShare = ableOrShare.add(expPayReqDetail.getMoney());
                } else {
                    expPayReqDetail.setSelfAmount(money.subtract(ky));
                    expPayReqDetail.setMoney(ky);
                    ableOrShare = ableOrShare.add(expPayReqDetail.getMoney());
                    deptMoney = deptMoney.add(expPayReqDetail.getSelfAmount());
                }
            } else {
                //全部用户自缴
                expPayReqDetail.setSelfAmount(money);
                expPayReqDetail.setMoney(BigDecimal.ZERO);
                deptMoney = deptMoney.add(expPayReqDetail.getSelfAmount());
            }
        }
        expPayReqDetail.setDeptMoney(deptMoney);
        expPayReqDetail.setAbleOrShare(ableOrShare);
    }
}
